package ide.ccf.ccproject;

import ide.ccf.ccproject.common.Utils;
import ide.ccf.ccproject.dialogs.SelectScopeDialog;

import java.util.Vector;

import org.eclipse.cdt.core.CConventions;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

/**
 * CCF项目模拟器
 *
 */
public class ProjectMonitor implements IResourceChangeListener, Runnable
{
	private IProject m_pro;
	@SuppressWarnings("rawtypes")
	private Vector m_filesAdded;
	@SuppressWarnings("rawtypes")
	private Vector m_filesRemoved;

	private final static String SOURCE_FILES = "SOURCES";
	private final static String HEADER_FILES = "HEADERS";
	private final static String FORM_FILES = "FORMS";
	private final static String RESOURCE_FILES = "RESOURCES";
	
	/**
	 * 构造器
	 */
	@SuppressWarnings("rawtypes")
	public ProjectMonitor() 
	{
		m_filesAdded = new Vector();
		m_filesRemoved = new Vector();
		
		IWorkspace ws = ResourcesPlugin.getWorkspace();
		ws.addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
	}
	
	/**
	 * 资源变化事件处理
	 */
	public void resourceChanged(IResourceChangeEvent event) 
	{
		m_filesAdded.clear();
		m_filesRemoved.clear();
		
		IResourceDelta delta = event.getDelta();
		
		if (delta.getKind() == IResourceDelta.ADDED || delta.getKind() == IResourceDelta.REMOVED || (delta.getFlags() & IResourceDelta.OPEN) != 0) 
		{
			if (isCCFProject(delta.getResource()))
				return;
		}
		
		handleResourceDeltas(delta);
		
		if (!m_filesAdded.isEmpty() || !m_filesRemoved.isEmpty()) 
		{
			Display.getDefault().syncExec(this);
		}
	}
	
	/**
	 * 是否CCF项目
	 * @param res
	 * @return
	 */
	public boolean isCCFProject(IResource res) 
	{
		if (res.getType() == IResource.PROJECT) 
		{
			IProject pro = (IProject)res;
			try 
			{
				if (pro.exists() && pro.isOpen() && pro.hasNature(CCFNature.NATURE_ID))
					return true;
			} 
			catch (CoreException e) 
			{
				e.printStackTrace();
			}
		}
		return false;
	}
	
	/**
	 * 处理资源变化
	 * @param delta
	 */
	@SuppressWarnings("unchecked")
	public void handleResourceDeltas(IResourceDelta delta)
	{
		IResourceDelta children[] = delta.getAffectedChildren();
		
		for (int i = 0; i < children.length; ++i) 
		{
			IResourceDelta child = children[i];
			IResource current = child.getResource();
			
			if (child.getKind() == IResourceDelta.ADDED) 
			{
				if (isCCFProject(current))
					return;			
				
				if (isValidFile(current))
					m_filesAdded.add(current);
			} 
			else if ((child.getKind() == IResourceDelta.REMOVED)) 
			{
				if (isCCFProject(current))
					return;		
				
				if (isValidFile(current))
					m_filesRemoved.add(current);
			} 
			else if ((child.getFlags() & IResourceDelta.OPEN) != 0) 
			{
				if (isCCFProject(current))
					return;
			}
			handleResourceDeltas(child);	
		}
	}
	
	/**
	 * 是否合法文件
	 * @param resource
	 * @return
	 */
	public boolean isValidFile(IResource resource)
	{
		if (resource.getType() != IResource.FILE)
			return false;
		
		m_pro = resource.getProject();
		
		if (isCCFProject(m_pro))
			return true;

		return false;
	}
	
	/**
	 * 分配文件类型
	 * @param remove
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected void distributeFileTypes(boolean remove) 
	{
		Vector files = m_filesAdded;
		
		if (remove)
			files = m_filesRemoved;
		
		Vector sources = new Vector();
		Vector headers = new Vector();
		Vector forms = new Vector();
		Vector resources = new Vector();
		
		for (int i = 0; i < files.size(); ++i) 
		{
			IFile file = (IFile)files.get(i);
			IProject pro = file.getProject();
			String name = file.getName();
			
			if (CConventions.validateSourceFileName(pro, name).isOK()) 
			{
				if (!Utils.isGeneratedSourceFile(name))
					sources.add(file);
			} 
			else if (CConventions.validateHeaderFileName(pro, name).isOK()) 
			{
				if (!Utils.isGeneratedHeaderFile(name))
					headers.add(file);
			} 
			else if (Utils.isFormFile(name)) 
			{
				forms.add(file);
			} 
			else if (Utils.isResourceFile(name)) 
			{
				resources.add(file);
			}
		}
		
		if (sources.isEmpty() && headers.isEmpty() && forms.isEmpty() && resources.isEmpty())
			return;

		IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
		SelectScopeDialog dlg = new SelectScopeDialog(win.getShell(), m_pro);
		
		if (remove) 
		{
			if (!sources.isEmpty())
				dlg.removeFiles(sources, SOURCE_FILES);
			
			if (!headers.isEmpty())
				dlg.removeFiles(headers, HEADER_FILES);
			
			if (!forms.isEmpty())
				dlg.removeFiles(forms, FORM_FILES);
			
			if (!resources.isEmpty())
				dlg.removeFiles(resources, RESOURCE_FILES);
		} 
		else 
		{
			if (!sources.isEmpty())
				dlg.addFiles(sources, SOURCE_FILES);
			
			if (!headers.isEmpty())
				dlg.addFiles(headers, HEADER_FILES);
			
			if (!forms.isEmpty())
				dlg.addFiles(forms, FORM_FILES);
			
			if (!resources.isEmpty())
				dlg.addFiles(resources, RESOURCE_FILES);
		}
		
		dlg.open();
	}

	/**
	 * 运行
	 */
	public void run() 
	{
		distributeFileTypes(false);
		distributeFileTypes(true);
	}
}